#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

#pragma once

class Lc_Changeable_Hist
{
	public:
		double * _data;
		double fix_max;
		double fix_min;
		double _max;
		double _min;
		double _step;
		int _NBINS;
		
		Lc_Changeable_Hist(int n_NBINS=400)
		{
			fix_max = 9999;
			fix_min = -9999;
			//_NBINS = 400;
			_max = 1.01;
			_min = -0.01;
			_NBINS = n_NBINS;
			_step = (_max - _min)/_NBINS;
			_data = new(double[_NBINS]);	
			memset(_data,0,sizeof(double)*_NBINS);
		};
		
		void Output(FILE * out =  NULL)
		{
			if(out == NULL)
			{
				for(int i = 0;i<_NBINS;i++) printf("%.1lf ",_data[i]);
				printf("\n");
			}
			else
			{
				for(int i = 0;i<_NBINS;i++) fprintf(out,"%lf\t",_data[i]);
			}
		}
		
		void fresh()
		{
			_step = (_max - _min)/_NBINS;
		}
		
		void Set(double Min,double Max)
		{
			_min = Min;
			_max = Max;
			fresh();
		}
		
		void SetMinMax(Lc_Changeable_Hist & other_hist)
		{
			SetMinMax(other_hist._min,other_hist._max);
		}

		
		
		void SetMinMax(double new_min, double new_max)
		{
			double new_step = (new_max - new_min)/_NBINS;
			
			double l1 = _min;			
			
			
			double * temp_data = new(double[_NBINS]);	
			memset(temp_data,0,sizeof(double)*_NBINS);
			double r1;
			
			for(int i = 0;i< _NBINS;i++)
			{
				r1 = l1 + _step;
				
				int idleft = floor( (l1 - new_min) / new_step );
				int idright = floor( (r1 - new_min) / new_step );
				
				if(idleft==idright)
				{
					if(idleft>=0 && idleft<_NBINS) temp_data[idleft]+=_data[i];
				}
				else if( idright - idleft == 1)
				{
					double temp_sep = new_min + new_step*idright;
					double rate1 = (temp_sep - l1)/_step;
					double rate2 = (r1 - temp_sep)/_step;
					if(idleft>=0 && idleft<_NBINS && rate1>0 ) temp_data[idleft]+= (_data[i]*rate1);
					if(idright>=0 && idright<_NBINS && rate2>0 ) temp_data[idright]+= (_data[i]*rate2);
				}
				
				l1 = r1;
			}
			
			
			
			memmove(_data,temp_data,sizeof(double)*_NBINS);
			delete[] temp_data;
			_min = new_min;
			_max = new_max;
			_step = new_step;
		}
		
		void trans_interval(double value)
		{
			double new_min = _min;
			double new_max = _max;
			
			if(value <= _min)
			{
				new_min = value-1e-1;
			}
			else if(value >= _max)
			{
				new_max = value+1e-1;
			}
			
			SetMinMax(new_min,new_max);
			
			
			printf("Chang Hist Interval to [%lf %lf] <- %lf\n", _min, _max,value);
			//system("pause");
			
		}
		
		
		int Get_Index(double value,int & flag)
		{
			int id = floor( (value - _min) / _step );
			if( id >= _NBINS || id<0)
			{
				
				trans_interval(value);
				flag = 1;
				return Get_Index(value,flag);
			}
			else
			{				
				return id;
			}			
		}
		
		int Add(double value)
		{
			
			int flag = 0;
			int id = Get_Index(value,flag);
			_data[id]+=1;
			return flag;
		}
				
};


class Lc_Score_Curve
{
	public:
		int _class_N;

		double * _sum;

		Lc_Changeable_Hist * _hist_data;
		
		Lc_Score_Curve(int n_class_N = 2)
		{
			_class_N = n_class_N;
			_hist_data = new(Lc_Changeable_Hist[_class_N]);
		}

		double GetMin(){ return _hist_data[0]._min;}
		double GetMax(){ return _hist_data[0]._max;}

		void Set(double min,double max)
		{
			for(int i = 0;i< _class_N;i++)
			{
				_hist_data[i].SetMinMax(min,max);
			}
		}

		void Output(FILE * out =  NULL)
		{
			if(out==NULL)
			{
				for(int i = 0;i<_class_N;i++)
				{
					_hist_data[i].Output();
					printf("\n");
				}
			}
			else
			{
				fprintf(out,"%lf\t%lf\t%d\t%d\n",_hist_data[0]._min,_hist_data[0]._max,_class_N,_hist_data[0]._NBINS);
				for(int i = 0;i<_class_N;i++)
				{
					_hist_data[i].Output(out);
					fprintf(out,"\n");
				}
			}

		}
		

		void Add(double value,int label)
		{

			if(label<0 || label>=_class_N) return;
			
			if(_hist_data[label].Add(value))
			{
				for(int i = 0;i<_class_N;i++)
				{
					if(i!=label) _hist_data[i].SetMinMax( _hist_data[label]);
				}
			}
		}
};
